package ds.safelock.security;

/**
 * This class provides methods to retrieve/generate random bytes
 * @author David Silva
 * @version 1.0
 */
public class Salt {

	/**
	 * Retrieves the data from the salt file
	 * @param home path to user home directory
	 * @param key key used to ensure that the salt is valid (MAC)
	 * @return the bytes that were previously wrote to the salt file
	 * @throws SaltNotFoundException if the file where the salt is stored doesn't exist
	 * @throws FileCorruptedException if somehow the salt file got corrupted
	 * @throws IOException if there's an I/O error while retrieving the data from the salt file
	 */
	public static byte[] getSalt(String home, char[] key) throws ds.safelock.exception.SaltNotFoundException,
																 ds.safelock.exception.FileCorruptedException,
																 java.io.IOException
	{
		try { 
			/* retrieve both salt and MAC */
			byte[] data = ds.safelock.io.FileHelper.read(home+ds.safelock.config.Configuration.FILE_SALT);
			byte[] len = new byte[4]; 
			System.arraycopy(data, (data.length-len.length), len, 0, len.length);
			int mac_size = ds.safelock.util.ByteHelper.byteArrayToInt(len);
			byte[] mac = new byte[mac_size];
			byte[] salt = new byte[(data.length-len.length - mac_size)];
			System.arraycopy(data, 0, salt, 0, salt.length);
			System.arraycopy(data, salt.length, mac, 0, mac.length);
			
			/* compute and compare both MACs */
			byte[] mac_comp = MAC.compute(salt, key, salt);
			if (!MAC.compareMACs(mac, mac_comp))
				throw new ds.safelock.exception.FileCorruptedException("invalid salt!");

			/* we're ok */
			return salt;
		}
		catch (java.io.FileNotFoundException e) { 
			throw new ds.safelock.exception.SaltNotFoundException("The salt file '"+home+
								ds.safelock.config.Configuration.FILE_SALT+"' does not exist!"); 
		}
	}

	/**
	 * Stores the given salt onto the default salt file
	 * @param home path to user home directory
	 * @param salt the data to be stored
	 * @param key the key used to compute the MAC for the given data
	 * @throws IOException if any error occurs while writing the salt
	 */
	public static void storeSalt(String home, final byte[] salt, char[] key) throws java.io.IOException
	{
		/* computes the MAC */
		byte[] mac = MAC.compute(salt, key, salt);
		/* MAC size in bytes*/
		byte[] len = ds.safelock.util.ByteHelper.intToByteArray(mac.length);
		/* init the final chunk of data */
		final byte[] _mac = new byte[salt.length+mac.length+4];

		/* copy the stuff onto the proper byte array */
		System.arraycopy(salt, 0, _mac, 0, salt.length);
		System.arraycopy(mac, 0,  _mac, salt.length, mac.length);
		System.arraycopy(len, 0,  _mac, (salt.length+mac.length), len.length);

		/* stores the data */
		ds.safelock.io.FileHelper.write(home+ds.safelock.config.Configuration.FILE_SALT, _mac);
	}
	
	/**
	 * Generates 1024 Bytes of secure random data
	 * @return byte array containing the random data, null if the algorithm specified for the RNG isn't available
	 */
	public static byte[] generateSalt()
	{
		try { 
			java.security.SecureRandom sr = java.security.SecureRandom.getInstance(
											ds.safelock.config.Configuration.SALT_ALGORITHM);
			final byte[] salt = new byte[ds.safelock.config.Configuration.SALT_SIZE];
			sr.nextBytes(salt);
			return salt;
		}
		catch (java.security.NoSuchAlgorithmException e) { }
		return null;
	}

	/**
	 * Generates numBytes Bytes of secure random data
	 * @param numBytes the number of bytes to be generated
	 * @return byte array containing the random data, null if the algorithm specified for the RNG isn't available
	 */
	public static byte[] generateSalt(int numBytes)
	{
		try { return java.security.SecureRandom.getInstance(ds.safelock.config.Configuration.SALT_ALGORITHM).generateSeed(numBytes); }
		catch (java.security.NoSuchAlgorithmException e) { }
		return null;
	}
}
